package vip.george.security.filter;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import vip.george.security.autoconfig.EncryptProperties;
import vip.george.security.constant.InterfaceSecurityConstant;
import vip.george.security.utils.AesUtil;
import vip.george.security.utils.RsaUtil;
import vip.george.security.wrapper.CommonRequestWrapper;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 替换请求体的过滤逻辑（接口解密的过滤器）
 *
 * @author wang
 * @since 2022-05-20
 **/
public class InterfaceEncryptFilter implements Filter {


    @Autowired
    private EncryptProperties encryptProperties;


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {

            //如果在白名单中，接口不会进行解密
            boolean inWhiteList = isInWhiteList((HttpServletRequest) request);
            if (inWhiteList) {
                chain.doFilter(request, response);
                return;
            }

            //文件上传请求直接跳过
            String contentType = request.getContentType();
            if (StringUtils.isNotBlank(contentType) && contentType.startsWith("multipart/form-data")) {
                chain.doFilter(request, response);
                return;
            }
            //如果是websocket请求直接跳过
            if (((HttpServletRequest) request).getServletPath().toLowerCase().endsWith("/websocket")) {
                chain.doFilter(request, response);
                return;
            }
            if (((HttpServletRequest) request).getMethod().equalsIgnoreCase("OPTIONS")) {
                chain.doFilter(request, response);
                return;
            }
            if (((HttpServletRequest) request).getMethod().equalsIgnoreCase("GET")) {
                chain.doFilter(request, response);
                return;
            }

            //转换自己的wrapper，实现多次读写
            CommonRequestWrapper requestWrapper = new CommonRequestWrapper((HttpServletRequest) request);


//            //GET请求解密
//            if (requestWrapper.getMethod().equalsIgnoreCase("GET")) {
//                Map<String, String[]> newParameterMap = requestWrapper.getParameterMap();
//                Map<String, String[]> parameterMap = requestWrapper.getParameterMap();
//                Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
//                for (Map.Entry<String, String[]> entry : entries) {
//                    String key = entry.getKey();
//                    String[] values = entry.getValue();
//                    String[] decryptValues = new String[values.length];
//                    for (int i = 0; i < values.length; i++) {
//                        decryptValues[i] = decryptMix(values[i], aesKeySecret);
//                    }
//                    newParameterMap.put(key,decryptValues);
//                }
//                requestWrapper.setParameterMap(newParameterMap);
//                chain.doFilter(requestWrapper, response);
//                return;
//            }

            //非GET请求解密（带请求体的）
            //读出json请求体
            String body = new String(requestWrapper.getBytes(), StandardCharsets.UTF_8);
            JSONObject jsonObject = JSON.parseObject(body);
            //得到前端对真实请求参数加密的密文（前端加密的方式要和后端保持一致）
            String content = jsonObject.getString(InterfaceSecurityConstant.HTTP_BODY_KEY);

            //解密后的真实数据
            String realData = null;
            //根据安全模式进行不同的解密方式
            EncryptProperties.SecurityMode model = EncryptProperties.SecurityMode.getByValue(encryptProperties.getSecurityMode());
            String aesKey = null;
            switch (model) {
                case RSA_AND_AES_MIX:
                    //获取经RSA对AES-KEY加密之后的AesKey-Secret
                    String aesKeySecret = requestWrapper.getHeader(InterfaceSecurityConstant.MIX_SECRET_MODEL_HEADER);
                    //先用RSA私钥解密AesKey-Secret,得到真正的AesKey
                    aesKey = RsaUtil.decryptByPrivateKey(aesKeySecret, encryptProperties.getRsaPrivateKey());
                    //再用真实的AesKey解密请求参数数据(注意：这个解析出来的json字符串，有可能是JsonObject,也有可能是JsonArray)
                    realData = AesUtil.decrypt(content, aesKey);
                    requestWrapper.setAttribute(InterfaceSecurityConstant.AES_KEY_REQUEST_ATTRIBUTE, aesKey);
                    break;
                case AES:
                    //AES秘钥
                    aesKey = encryptProperties.getAesKey();
                    realData = AesUtil.decrypt(content, aesKey);
                    requestWrapper.setAttribute(InterfaceSecurityConstant.AES_KEY_REQUEST_ATTRIBUTE, aesKey);
                    break;
                default:
                    throw new RuntimeException("不支持的加密模式");
            }
            //重置json请求体，保证下游业务无感知获取数据
            requestWrapper.setBytes(realData.getBytes(StandardCharsets.UTF_8));
            //往下执行过滤器链
            chain.doFilter(requestWrapper, response);
        } catch (Exception e) {
            // 异常捕获，发送到error controller
//            request.setAttribute(Constant.FILTER_ERROR_KEY, e);
            //将异常分发到/error/exthrow控制器
            request.getRequestDispatcher("/error").forward(request, response);
        }
    }



    /**
     * 请求连接是否在白名单（URL是否在白名单中，如果不在白名单则需要过滤，如果在白名单中则不需要过滤）
     *
     * @param request
     * @return
     */
    private boolean isInWhiteList(HttpServletRequest request) {
        String servletPath = request.getServletPath();
        // 放行不过滤的URL
        return encryptProperties.getExcludeUrls().contains(servletPath);
    }

    @Override
    public void destroy() {

    }

}